////////////////////////////////////////////////////////////////////////////////
//
//  The MIT License
//
//  Copyright (c) 2008 - 2009. Dimarik
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////

package ru.goodcore.service
{

import flash.errors.IllegalOperationError;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;

import ru.goodcore.net.URI;
import ru.goodcore.transport.AbstractTransport;
import ru.goodcore.transport.HTTPLongPollTransport;
import ru.goodcore.transport.HTTPTransport;
import ru.goodcore.transport.LocalConnectionTransport;



/**
 *  @author				Dimarik
 *  @version			1.0
 *  @langversion		3.0
 *  @playerversion		9.0
 *
 */
public class AbstractService extends EventDispatcher {

	//---------------------------------------------------------------------
	//
	//   Constructor
	//
	//---------------------------------------------------------------------

	public function AbstractService() {
		super();
	}

	//---------------------------------------------------------------------
	//
	//   Properties
	//
	//---------------------------------------------------------------------

	//-------------------------------------
	//  uri
	//-------------------------------------
	/**
	 * @private
	 */
	private var _uri:	URI;

	public function get uri():URI {
		return this._uri;
	}

	public function set uri(value:URI):void {
		if (this._uri == value) return;
		this._uri = value;
		this.assignTransport();
	}


	//-------------------------------------
	//  connected
	//-------------------------------------
	public function get connected():Boolean {
		return this.transport ? this.transport.connected : false;
	}

	//---------------------------------------------------------------------
	//
	//   Protected variables
	//
	//---------------------------------------------------------------------

	//-------------------------------------
	//  transport
	//-------------------------------------

	protected var $transport:	AbstractTransport;

	public function get transport():AbstractTransport {
		return this.$transport;
	}

	//---------------------------------------------------------------------
	//
	//   Private variables
	//
	//---------------------------------------------------------------------

	/**
	 * @private
	 */
	private var _responder:		IResponder;

	//---------------------------------------------------------------------
	//
	//   Public methods
	//
	//---------------------------------------------------------------------

	public function connect(uri:URI = null):void {
		if (uri) 
			this.uri = uri;

		if (!this.uri)
			throw new IllegalOperationError('Service has not URI');

		if (this.connected) {
			this.close();
		}

		this.$transport.connect(uri);
	}



	public function send(options:Object = null, responder:Object = null):void {
		if (!this.connected) {
			throw new IllegalOperationError('Service not connected');
			//this.connect();
		}
		
		if (responder) {

			if ( !(responder is IResponder) ) {
				this._responder = new Responder(responder.result, responder.fail);
			} else {
				this._responder = responder as IResponder;
			}

		} else {
			this._responder = null;
		}

		this.$transport.send(options);
	}



	public function close():void {
		this.$transport.removeEventListener(ProgressEvent.SOCKET_DATA,	this.handler_data);
		this.$transport.removeEventListener(Event.CONNECT,				this.handler_connect);
		this.$transport.removeEventListener(Event.COMPLETE,				this.handler_complete);
		this.$transport.removeEventListener(Event.CLOSE,				this.handler_close);
		this.$transport.removeEventListener(IOErrorEvent.IO_ERROR,		this.handler_ioError);

		if (this.$transport) this.$transport.close();
	}

	//---------------------------------------------------------------------
	//
	//   Protected methods
	//
	//---------------------------------------------------------------------

	protected function assignTransport():void {
		var scheme:String = this._uri.scheme;

		switch (scheme) {
			case URI.SCHEME_HTTP:
			case URI.SCHEME_HTTPS: {
				this.$transport = new HTTPTransport();
				break;
			}

			case URI.SCHEME_HTTP_LONG_POLL: {
				this.$transport = new HTTPLongPollTransport();
				break;
			}

			case URI.SCHEME_FILE: {
				//this.transport = new FileTransport()
				break;
			}

			case URI.SCHEME_LOCAL_CONNECTION: {
				this.$transport = new LocalConnectionTransport();
				break;
			}
		}

		if (this.$transport) {
			this.$transport.addEventListener(ProgressEvent.SOCKET_DATA,	this.handler_data);
			this.$transport.addEventListener(Event.CONNECT,				this.handler_connect);
			this.$transport.addEventListener(Event.COMPLETE,			this.handler_complete);
			this.$transport.addEventListener(Event.CLOSE,				this.handler_close);
			this.$transport.addEventListener(IOErrorEvent.IO_ERROR,		this.handler_ioError);
		}
	}

	//---------------------------------------------------------------------
	//
	//   Private methods
	//
	//---------------------------------------------------------------------

	/**
	 * @private
	 */
	private function $connect():void {
		
	}

	//---------------------------------------------------------------------
	//
	//   Events handlers
	//
	//---------------------------------------------------------------------

	/**
	 * @private
	 */
	private function handler_connect(event:Event):void {
		super.dispatchEvent(event);
	}

	/**
	 * @private
	 */
	private function handler_data(event:Event):void {
		super.dispatchEvent(event);
		if (this._responder) {
			this._responder.result( (event.target as AbstractTransport).data );
		}
	}

	/**
	 * @private
	 */
	private function handler_complete(event:Event):void {
		super.dispatchEvent(event);
		if (this._responder) {
			this._responder.result( (event.target as AbstractTransport).data );
		}
	}

	/**
	 * @private
	 */
	private function handler_close(event:Event):void {
		super.dispatchEvent(event);
	}

	/**
	 * @private
	 */
	private function handler_ioError(event:Event):void {
		super.dispatchEvent(event);
		if (this._responder)
			this._responder.fault( (event.target as AbstractTransport).data );
	}

}
}